package org.jef.core.util;

import sun.misc.Unsafe;

import javax.management.ReflectionException;
import java.lang.reflect.*;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

/**
 * @program: Jef-orm
 * @description: 原子操作
 * @author: Cheng Zhi
 * @create: 2023-09-09 21:00
 **/
public class UnsafeUtils {

    static Unsafe UNSAFE = null;

    static {
        try {
            UNSAFE = reflectGetUnsafe();
        } catch (NoSuchFieldException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        }
    }

    /**
     * 反射获取unsafe对象，引用Unsafe需使用如下反射方式，否则会抛出异常java.lang.SecurityException: Unsafe
     * @return
     * @throws NoSuchFieldException
     * @throws IllegalAccessException
     */
    public static Unsafe reflectGetUnsafe() throws NoSuchFieldException, IllegalAccessException {
        Field theUnsafe = Unsafe.class.getDeclaredField("theUnsafe");
        theUnsafe.setAccessible(true); // 禁止访问权限检查（访问私有属性时需要加上）
        return (Unsafe) theUnsafe.get(null);
    }

    /**
     * 不使用反射直接创造对象，注意类的构造方法不会被执行， 注意该方法会导致类的默认属性失效，默认属性会变为JVM的默认属性。
     * @param clz
     * @return 被构造的对象
     */
    @SuppressWarnings("unchecked")
    public final static <T> T newInstanceUnsalf(Class<T> clz){
        try {
            return (T) UNSAFE.allocateInstance(clz);
        } catch (InstantiationException e) {
            throw new IllegalStateException(e.getCause());
        }
    }

    /**
     * 使用反射获取对象
     * @param clz
     * @param <T>
     * @return
     */
    public final static <T> T newInstance(Class<T> clz){
        try {
            return (T) clz.newInstance();
        } catch (InstantiationException | IllegalAccessException e) {
            throw new IllegalStateException(e.getCause());
        }
    }

    /**
     * 获取一个字段的内存地址
     * @param field
     * @return
     */
    public static long getFiledSet(Field field) {
        return UNSAFE.objectFieldOffset(field);
    }

    /**
     * 给对象强制赋值
     * @param target  目标对象
     * @param offset  内存地址
     * @param value   值
     */
    public static void forcedSetValue(Object target, Field field, Object value) {
        UNSAFE.putObject(target, UNSAFE.objectFieldOffset(field), value);
        /*if (value instanceof Long) {
            UNSAFE.putLong(target, offset, (Long) value);
        } else if (value instanceof Integer) {
            UNSAFE.putInt(target, offset, (Integer) value);
        } else if (value instanceof Float) {
            UNSAFE.putFloat(target, offset, (Float) value);
        } else if (value instanceof Boolean) {
            UNSAFE.putBoolean(target, offset, (Boolean) value);
        } else {
            UNSAFE.putObject(target, offset, value);
        }*/
    }

    /**
     * 给对象强制赋值
     * @param target  目标对象
     * @param offset  内存地址
     * @param value   值
     */
    public static void forcedSetValue(Object target, long offset, Object value, Class<?> fieldType) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {

        if (value == null) {
            return;
        }

        if (fieldType == long.class) {
            if (!(value instanceof Long)) {
                value = Long.valueOf(value.toString());
            }
            UNSAFE.putLong(target, offset, (Long) value);
        } else if (fieldType == int.class) {
            if (!(value instanceof Integer)) {
                value = Integer.valueOf(value.toString());
            }
            UNSAFE.putInt(target, offset, (Integer) value);
        } else if (fieldType == Float.class) {
            if (!(value instanceof Float)) {
                value = Float.valueOf(value.toString());
            }
            UNSAFE.putFloat(target, offset, (Float) value);
        } else if (fieldType == boolean.class) {
            if (!(value instanceof Boolean)) {
                value = Boolean.valueOf(value.toString());
            }
            UNSAFE.putObject(target, offset, (Boolean) value);
        } else if (fieldType == String.class) {
            // 判断如果需要强转，则使用String.valueOf();
            if (!(value instanceof String)) {
                value = String.valueOf(value);
            }
            UNSAFE.putObject(target, offset, value);
        } else {
            UNSAFE.putObject(target, offset, value);
        }
    }

    /**
     * 强制获取字段值
     * @param field
     * @return
     */
    public static Object forcedGetValue(Object o, Field field) {

        long fieldOffset = getFiledSet(field);
        Type genericType = field.getGenericType();
        switch (genericType.getTypeName()) {
            case "int":
                return UNSAFE.getInt(o, fieldOffset);
            case "long":
                return UNSAFE.getLong(o, fieldOffset);
            case "float":
                return UNSAFE.getFloat(o, fieldOffset);
            case "double":
                return UNSAFE.getDouble(o, fieldOffset);
            default:
                return UNSAFE.getObject(o, fieldOffset);
        }

    }

    /**
     * 将map转换为对象
     * @param map
     * @param clazz
     * @param <T>
     * @return
     */
    public static <T> T mapToEntity(Map map, Class<T> clazz) {
        T t = newInstance(clazz);
        try {
            Class<? super T> superclass = clazz.getSuperclass();
            setValue(map, t, (Class<? super T>) superclass);
            setValue(map, t, (Class<? super T>) clazz);
        } catch (Exception e) {
            e.printStackTrace();
        }

        return t;
    }

    private static <T> void setValue(Map map, T t, Class<? super T> superclass) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
        for (Field field : superclass.getDeclaredFields()) {
            long offset = UnsafeUtils.getFiledSet(field);
            Class<?> type = field.getType();
            Object o = map.get(field.getName());
            if (!isBaseType(type) && o instanceof Map) {
                o = mapToEntity((Map) o, type);
            }
            if (!isBaseType(type) && o instanceof List) {
                // 获取泛型
                Class<?> genericTypeClass = null;
                if (type.isAssignableFrom(List.class)) {
                    ParameterizedType parameterizedType = (ParameterizedType) field.getGenericType();
                    Type[] actualTypeArguments = parameterizedType.getActualTypeArguments();
                    if (actualTypeArguments.length > 0) {
                        genericTypeClass = (Class<?>) actualTypeArguments[0];
                    }
                }
                List list = new ArrayList();
                for (Object obj : (List)o) {
                    Class<?> aClass = obj.getClass();
                    if (!isBaseType(type) && obj instanceof Map) {
                        obj = mapToEntity((Map) obj, genericTypeClass);
                    }
                    list.add(obj);
                }
                o = list;
            }
            forcedSetValue(t, offset, o, type);
        }
    }

    /**
     * 判断是否基础常用类型
     * @param fieldType
     * @return
     */
    private static boolean isBaseType(Class<?> fieldType) {

        if (fieldType == Long.class || fieldType == long.class || fieldType == Integer.class || fieldType == int.class || fieldType == Float.class
                || fieldType == Boolean.class || fieldType == String.class || fieldType == Object.class
        ) {
            return true;
        }

        return false;
    }
}
